
package tests;

import static org.junit.Assert.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.Random;
import java.util.UUID;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import sourceFiles.CentralComputer;
import sourceFiles.ExtremeRideEntry;
import sourceFiles.IRide;
import sourceFiles.Ride;
import sourceFiles.RideEntry;
import sourceFiles.SupervisorStation;

import Exceptions.InvalidAgeParam;
import Exceptions.InvalidCapacity;
import Exceptions.InvalidHeightParam;
import Exceptions.InvalidRideId;
import Exceptions.InvalidRideName;
import Exceptions.XMLRidesParserException;
import Exceptions.CentralComputerExceptions.RideIDDoesntExist;
/**
 * @author LASO-Team
 *
 */
public class SupervisorStationTestCC {
	//TODO:  add to the tests, replacing the stub-tests
	static private String masterXMLFilePath;
	static private String copyXMLFilePath;
	static private int numOfInitialRides;

	
	static private final int RANDOM_TEST_SIZE = 7;
	static private final int[] EDGE_OF_LEGAL_INT_VALUES = { 1, 2 };
	static private final int[] EDGE_OF_ILLEGAL_INT_VALUES = { -1, 0 };
	static private final int TEST_SIZE = RANDOM_TEST_SIZE
			+ EDGE_OF_LEGAL_INT_VALUES.length;
	private static final String IN_PROJECT_PATH_TO_TESTS = "\\src\\tests";
	static private final int MAX_RANDOM = 200;
	static private String[] legalRideNames;
	static private int[] legalMaxCapacities;
	static private int[] legalMinAges;
	static private int[] legalMinHeights;
	static private int[] legalRideIDs;
	static private boolean[] isExtremeRides;
	static private int[] illegalMaxCapacities;
	static private int[] illegalMinAges;
	static private int[] illegalMinHeights;
	static private int[] illegalRideIDs;
	static private int[] nonExistingLegalRideIDs;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		assertTrue(EDGE_OF_LEGAL_INT_VALUES.length == EDGE_OF_ILLEGAL_INT_VALUES.length);
		//TODO:  add to the tests, replacing the stub-tests
		String currentPath = new java.io.File(".").getCanonicalPath();
		currentPath =  currentPath + IN_PROJECT_PATH_TO_TESTS;
		masterXMLFilePath = currentPath + "\\TestsMaster.xml";
		copyXMLFilePath = currentPath + "\\results\\ResultsIntegrationSupervisorStationCC.xml";

		LinkedList<Integer> legalMaxCapacitiesList = new LinkedList<Integer>();
		LinkedList<Integer> legalMinAgesList = new LinkedList<Integer>();
		LinkedList<Integer> legalMinHeightsList = new LinkedList<Integer>();
		LinkedList<Integer> legalRideIDsList = new LinkedList<Integer>();

		LinkedList<Integer> illegalMaxCapacitiesList = new LinkedList<Integer>();
		LinkedList<Integer> illegalMinAgesList = new LinkedList<Integer>();
		LinkedList<Integer> illegalMinHeightsList = new LinkedList<Integer>();
		LinkedList<Integer> illegalRideIDsList = new LinkedList<Integer>();

		LinkedList<Integer> nonExistinglegalRideIDsListList = new LinkedList<Integer>();

		int numOfEdgeTests = EDGE_OF_LEGAL_INT_VALUES.length;
		for (int i = 0; i < numOfEdgeTests; i++) { // init the legal value first
			legalMaxCapacitiesList.add(EDGE_OF_LEGAL_INT_VALUES[i]);
			legalMinAgesList.add(EDGE_OF_LEGAL_INT_VALUES[i]);
			legalMinHeightsList.add(EDGE_OF_LEGAL_INT_VALUES[i]);
			legalRideIDsList.add(EDGE_OF_LEGAL_INT_VALUES[i]);
			illegalMaxCapacitiesList.add(EDGE_OF_ILLEGAL_INT_VALUES[i]);
			illegalMinAgesList.add(EDGE_OF_ILLEGAL_INT_VALUES[i]);
			illegalMinHeightsList.add(EDGE_OF_ILLEGAL_INT_VALUES[i]);
			illegalRideIDsList.add(EDGE_OF_ILLEGAL_INT_VALUES[i]);
		}
		Random rand = new Random();
		int newRandID;
		for (int i = 0; i < RANDOM_TEST_SIZE; i++) {

			newRandID = rand.nextInt(MAX_RANDOM) + 1;
			while (legalRideIDsList.contains(newRandID)) {
				newRandID = rand.nextInt(MAX_RANDOM) + 1;
			}

			legalMaxCapacitiesList.add(rand.nextInt(MAX_RANDOM) + 1);
			legalMinAgesList.add(rand.nextInt(MAX_RANDOM) + 1);
			legalMinHeightsList.add(rand.nextInt(MAX_RANDOM) + 1);
			legalRideIDsList.add(newRandID);

			illegalMaxCapacitiesList.add(-rand.nextInt(MAX_RANDOM));
			illegalMinAgesList.add(-rand.nextInt(Integer.MAX_VALUE));
			illegalMinHeightsList.add(-rand.nextInt(Integer.MAX_VALUE));
			illegalRideIDsList.add(-rand.nextInt(Integer.MAX_VALUE));

		}

		// add legal ride IDs that will not be created
		for (int i = 0; i < TEST_SIZE; i++) {
			newRandID = rand.nextInt(MAX_RANDOM) + 1;
			while (legalRideIDsList.contains(newRandID)) {
				newRandID = rand.nextInt(MAX_RANDOM) + 1;
			}
			nonExistinglegalRideIDsListList.add(newRandID);
		}

		assertTrue(legalRideIDsList.size() == TEST_SIZE);

		legalRideNames = new String[TEST_SIZE];
		legalMaxCapacities = new int[TEST_SIZE];
		legalMinAges = new int[TEST_SIZE];
		legalMinHeights = new int[TEST_SIZE];
		legalRideIDs = new int[TEST_SIZE];
		isExtremeRides = new boolean[TEST_SIZE];
		illegalMaxCapacities = new int[TEST_SIZE];
		illegalMinAges = new int[TEST_SIZE];
		illegalMinHeights = new int[TEST_SIZE];
		illegalRideIDs = new int[TEST_SIZE];
		nonExistingLegalRideIDs = new int[TEST_SIZE];
		for (int i = 0; i < TEST_SIZE; i++) {
			legalRideNames[i] = UUID.randomUUID().toString();
			legalMaxCapacities[i] = legalMaxCapacitiesList.get(i);
			legalMinAges[i] = legalMinAgesList.get(i);
			legalMinHeights[i] = legalMinHeightsList.get(i);
			legalRideIDs[i] = legalRideIDsList.get(i);
			isExtremeRides[i] = rand.nextBoolean();

			illegalMaxCapacities[i] = illegalMaxCapacitiesList.get(i);
			illegalMinAges[i] = illegalMinAgesList.get(i);
			illegalMinHeights[i] = illegalMinHeightsList.get(i);
			illegalRideIDs[i] = illegalRideIDsList.get(i);

			nonExistingLegalRideIDs[i] = nonExistinglegalRideIDsListList.get(i);
		}
		return;
	}
	
	@Before
	public void setUp() throws XMLRidesParserException, InvalidRideName, InvalidCapacity, InvalidAgeParam, InvalidHeightParam, IOException {
		copySourceFile();
	}
	
	private void copySourceFile() throws FileNotFoundException, IOException {
		InputStream inStream = null;
		OutputStream outStream = null;

		File afile = new File(masterXMLFilePath);
		File bfile = new File(copyXMLFilePath);

		inStream = new FileInputStream(afile);
		outStream = new FileOutputStream(bfile);

		byte[] buffer = new byte[1024];

		int length;
		// copy the file content in bytes
		while ((length = inStream.read(buffer)) > 0) {

			outStream.write(buffer, 0, length);
		}
		inStream.close();
		outStream.close();
	}
	private boolean checkIfExtreme (RideEntry rideEntry){
		if (rideEntry.getClass().equals(ExtremeRideEntry.class)){
			return true;
		}
		else{
			return false;
		}
	}
	
	
	private int findNonExistindRandomRideID(CentralComputer cc) {
		Random rand = new Random();
		int newRandID = 0;
		boolean doesIDExists = true;
		while (doesIDExists) {
			newRandID = rand.nextInt(MAX_RANDOM) + 1;
			doesIDExists = false;
			LinkedList<IRide> currentRides = cc.getRidesList();
			for (int i = 0; i < currentRides.size(); i++) {
				if (currentRides.get(i).getRideID() == newRandID) {
					doesIDExists = true;
					break;
				}
			}
		}
		return newRandID;
	}
	

	/**
	 * this method tests that we can only enter a name that is not null.
	 * 
	 * @throws XMLRidesParserException
	 * @throws InvalidHeightParam
	 * @throws InvalidAgeParam
	 * @throws InvalidCapacity
	 */
	@Test
	public void testCreateNewRide1() throws InvalidCapacity, InvalidAgeParam,
			InvalidHeightParam, XMLRidesParserException {
		SupervisorStation supervisor = new SupervisorStation(
				new CentralComputer(copyXMLFilePath));
		try {
			supervisor.createNewRide(null, isExtremeRides[0],
					legalMaxCapacities[0], legalMinAges[0], legalMinHeights[0]);
			fail("tried to create with a null pointer as a name string");
		} catch (InvalidRideName e) {
		}
	}
	
	
	

	/**
	 * This method tests that we cannot enter an invalid capacity.
	 * 
	 * @throws XMLRidesParserException
	 * @throws InvalidHeightParam
	 * @throws InvalidAgeParam
	 * @throws InvalidRideName
	 */
	@Test
	public void testCreateNewRide2() throws InvalidRideName, InvalidAgeParam,
			InvalidHeightParam, XMLRidesParserException {
		SupervisorStation supervisor = new SupervisorStation(
				new CentralComputer(copyXMLFilePath));	
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
						illegalMaxCapacities[i], legalMinAges[i],
						legalMinHeights[i]);
				System.out.println(legalRideNames[i]);
				System.out.println(isExtremeRides[i]);
				System.out.println(illegalMaxCapacities[i]);
				System.out.println(legalMinAges[i]);
				System.out.println(legalMinHeights[i]);
				fail("tried to create a new ride with an illegalMaxCapacity["
						+ i + " = " + illegalMaxCapacities[i]);
			} catch (InvalidCapacity e) {
			}
		}

	}

	/**
	 * This method tests that we cannot enter an invalid age.
	 * 
	 * @throws XMLRidesParserException
	 * @throws InvalidHeightParam
	 * @throws InvalidCapacity
	 * @throws InvalidRideName
	 */
	@Test
	public void testCreateNewRide3() throws InvalidRideName, InvalidCapacity,
			InvalidHeightParam, XMLRidesParserException {
		SupervisorStation supervisor = new SupervisorStation(
				new CentralComputer(copyXMLFilePath));
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
						legalMaxCapacities[i], illegalMinAges[i],
						legalMinHeights[i]);
				fail("tried to create a new ride with an illegalMinAge[" + i
						+ " = " + illegalMinAges[i]);
			} catch (InvalidAgeParam e) {
			}
		}
	}

	/**
	 * This method tests that we cannot enter an invalid height.
	 * 
	 * @throws XMLRidesParserException
	 * @throws InvalidAgeParam
	 * @throws InvalidCapacity
	 * @throws InvalidRideName
	 */
	@Test
	public void testCreateNewRide4() throws InvalidRideName, InvalidCapacity,
			InvalidAgeParam, XMLRidesParserException {
		SupervisorStation supervisor = new SupervisorStation(
				new CentralComputer(copyXMLFilePath));
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
						legalMaxCapacities[i], legalMinAges[i],
						illegalMinHeights[i]);
				fail("tried to create a new ride with an illegalMinHeight[" + i
						+ " = " + illegalMinHeights[i]);
			} catch (InvalidHeightParam e) {
			}
		}
	}

	/**
	 * This method tests that we can create a ride with legal parameters.
	 */
	@Test
	public void testCreateNewRide5() throws Exception {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		numOfInitialRides = cc.getRidesList().size();
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
					legalMaxCapacities[i], legalMinAges[i], legalMinHeights[i]);
		}

		Ride currRide;
		for (int i = 0; i < TEST_SIZE; i++) {
			currRide = (Ride) cc.getRidesList().get(i + numOfInitialRides);
			assertTrue(currRide.getMaxCapacity() == legalMaxCapacities[i]);
			assertTrue(currRide.getMinimumAge() == legalMinAges[i]);
			assertTrue(currRide.getMinimumHeight() == legalMinHeights[i]);
			assertTrue(currRide.getRideName().equals(legalRideNames[i]));
			assertTrue(checkIfExtreme(cc.getRidesCatalog().get(i + numOfInitialRides)) == isExtremeRides[i]);
			assertTrue(currRide.getRideID() == (i + numOfInitialRides + 1) );
		}
	}

	 /**
	 * this method tests that we cannot edit a ride with ID smaller than 1.
	 */
	@Test
	public void testEditRideParams1() throws InvalidRideName, InvalidCapacity,
			InvalidAgeParam, InvalidHeightParam, XMLRidesParserException, RideIDDoesntExist {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.editRideParams(illegalRideIDs[i],
						legalMaxCapacities[i], legalMinAges[i],
						legalMinHeights[i]);
				fail("tried to update a ride with illegalRideIDs[" + i + "] = "
						+ illegalRideIDs[i]);
			} catch (InvalidRideId e) {
			}
		}
	}

	
	 /**
	 * this method tests that we cannot edit a ride with capacity smaller than
	 * 1.
	 */
	@Test
	public void testEditRideParams2() throws InvalidRideId, InvalidAgeParam,
			InvalidHeightParam, RideIDDoesntExist, XMLRidesParserException {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.editRideParams(legalRideIDs[i],
						illegalMaxCapacities[i], legalMinAges[i],
						legalMinHeights[i]);
				fail("tried to update a ride with illegalMaxCapacities[" + i
						+ "] = " + illegalMaxCapacities[i]);
			} catch (InvalidCapacity e) {
			}
		}
	}

	
	 /**
	 * this method tests that we cannot edit a ride with minimal age smaller
	 * than 1.
	 */
	@Test
	public void testEditRideParams3() throws InvalidRideId, InvalidCapacity,
			InvalidHeightParam, RideIDDoesntExist, XMLRidesParserException, InvalidRideName, InvalidAgeParam {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
					legalMaxCapacities[i], legalMinAges[i], legalMinHeights[i]);
		}
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.editRideParams(cc.getRidesList().get(i).getRideID(),
						legalMaxCapacities[i], illegalMinAges[i],
						legalMinHeights[i]);
				fail("tried to update a ride with illegalMinAges[" + i + "] = "
						+ illegalMinAges[i]);
			} catch (InvalidAgeParam e) {
			}
		}
	}

	 /**
	 * this method tests that we cannot edit a ride with minimal height
	 smaller
	 * than 1.
	 */
	@Test
	public void testEditRideParams4() throws InvalidRideId, InvalidCapacity,
			InvalidAgeParam, RideIDDoesntExist, XMLRidesParserException, InvalidRideName, InvalidHeightParam {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
					legalMaxCapacities[i], legalMinAges[i], legalMinHeights[i]);
		}
		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.editRideParams(cc.getRidesList().get(i).getRideID(),
						legalMaxCapacities[i], legalMinAges[i],
						illegalMinHeights[i]);
				fail("tried to update a ride with illegalMinHeights[" + i
						+ "] = " + illegalMinHeights[i]);
			} catch (InvalidHeightParam e) {
			}
		}
	}

	
	 /**
	 * this method tests that we cannot edit a ride which does not exist.
	 */
	@Test
	public void testEditRideParams5() throws InvalidRideName, InvalidCapacity,
			InvalidAgeParam, InvalidHeightParam, XMLRidesParserException,
			InvalidRideId, RideIDDoesntExist {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
					legalMaxCapacities[i], legalMinAges[i], legalMinHeights[i]);
		}
		
		int newRandID = findNonExistindRandomRideID(cc);
		
//		for (int i = 0; i < TEST_SIZE; i++) {
			try {
				supervisor.editRideParams(newRandID,
						legalMaxCapacities[2], legalMinAges[2],
						legalMinHeights[2]);
				fail("tried to update a ride with value of " + newRandID);
			} catch (RideIDDoesntExist e) {
			}
//		}
	}

	
	 /**
	 * this method tests that we can edit a ride with valid parameters.
	 */
	 @Test
	public void testEditRideParams6() throws Exception {
		CentralComputer cc = new CentralComputer(copyXMLFilePath);
		SupervisorStation supervisor = new SupervisorStation(cc);
		numOfInitialRides = cc.getRidesList().size();
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.createNewRide(legalRideNames[i], isExtremeRides[i],
					legalMaxCapacities[i], legalMinAges[i], legalMinHeights[i]);
		}
		for (int i = 0; i < TEST_SIZE; i++) {
			supervisor.editRideParams(cc.getRidesList().get(i).getRideID(),
					legalMaxCapacities[TEST_SIZE - (i+1)], legalMinAges[TEST_SIZE
							- (i+1)], legalMinHeights[TEST_SIZE - (i+1)]);
		}

		Ride currRide;
		for (int i = 0; i < TEST_SIZE; i++) {
			currRide = (Ride) cc.getRidesList().get(i);
			assertTrue(currRide.getMaxCapacity() == legalMaxCapacities[TEST_SIZE - (i+1)]);
			assertTrue(currRide.getMinimumAge() == legalMinAges[TEST_SIZE - (i+1)]);
			assertTrue(currRide.getMinimumHeight() == legalMinHeights[TEST_SIZE - (i+1)]);
//			assertTrue(currRide.getRideName().equals(legalRideNames[i]));
//			assertTrue(checkIfExtreme(cc.getRidesCatalog().get(i)) == isExtremeRides[i]);
			assertTrue(currRide.getRideID() == i + 1);
		}
	}

}
